import { isOverlap } from '@ibiz-template/core';
import {
  calcLayoutHeightWidth,
  FormNotifyState,
  verifyFormGroupLogic,
  IFormDetailController,
  IFormDetailContainerController,
  calcDynaClass,
} from '@ibiz-template/runtime';
import { IDEFormDetail } from '@ibiz/model-core';
import { useNamespace } from '@ibiz-template/vue3-util';
import { FormController } from '../../form/form.controller';
import { FormDetailState } from './form-detail.state';

export class FormDetailController<T extends IDEFormDetail = IDEFormDetail>
  implements IFormDetailController
{
  /**
   * 表单成员模型
   *
   * @author lxm
   * @date 2022-08-24 20:08:19
   * @type {T}
   */
  readonly model: T;

  /**
   * 表单项状态
   *
   * @author chitanda
   * @date 2023-01-04 09:01:04
   * @type {FormDetailState}
   */
  state: FormDetailState;

  /**
   * 表单控制器
   *
   * @author lxm
   * @date 2022-08-24 22:08:59
   * @type {FormController}
   */
  readonly form: FormController;

  /**
   * 父容器控制器(除了表单分页都存在)
   *
   * @author lxm
   * @date 2022-08-24 22:08:59
   * @type {FormController}
   */
  readonly parent?: IFormDetailContainerController;

  /**
   * 表单数据
   *
   * @author lxm
   * @date 2022-09-01 22:09:48
   * @readonly
   */
  get data(): IData {
    return this.form.data;
  }

  /**
   * 获取容器类名集合
   * @author lxm
   * @date 2023-08-02 06:06:12
   * @readonly
   * @type {string[]}
   */
  get containerClass(): string[] {
    return [...this.state.class.container, ...this.state.class.containerDyna];
  }

  /**
   * 获取标题类名集合
   * @author lxm
   * @date 2023-08-02 06:16:48
   * @readonly
   * @type {string[]}
   */
  get labelClass(): string[] {
    return [...this.state.class.label, ...this.state.class.labelDyna];
  }

  /**
   * Creates an instance of FormDetailController.
   * @author lxm
   * @date 2022-08-24 20:08:22
   * @param {T} model
   */
  constructor(
    model: T,
    form: FormController,
    parent?: IFormDetailContainerController,
  ) {
    this.model = model;
    this.form = form;
    this.parent = parent;
    this.state = this.createState();
  }

  /**
   * 子类不可覆盖或重写此方法，在 init 时需要重写的使用 onInit 方法。
   *
   * @author lxm
   * @date 2022-08-18 22:08:30
   * @returns {*}  {Promise<void>}
   */
  async init(): Promise<void> {
    await this.onInit();
  }

  protected async onInit(): Promise<void> {
    this.state.showMoreMode = this.model.showMoreMode!;

    // 初始化布局参数
    const { layoutPos, detailType, sysCss, labelSysCss } = this.model;

    // 初始化高宽
    if (layoutPos) {
      const { width, height } = calcLayoutHeightWidth(layoutPos);
      this.state.layout.width = `${width}`;
      this.state.layout.height = `${height}`;
    }

    // 给col添加各自类型的类名
    const ns = useNamespace('panel-col');
    this.state.layout.extraClass.push(ns.m(detailType!.toLowerCase()));

    if (sysCss?.cssName) {
      this.state.class.container.push(sysCss.cssName);
    }

    if (labelSysCss?.cssName) {
      this.state.class.label.push(labelSysCss.cssName);
    }
  }

  /**
   * 创建表单状态对象
   *
   * @author chitanda
   * @date 2023-01-04 10:01:00
   * @protected
   * @return {*}  {FormDetailState}
   */
  protected createState(): FormDetailState {
    return new FormDetailState(this.parent?.state);
  }

  /**
   * 表单数据变更通知(由表单控制器调用)
   *
   * @author lxm
   * @date 2022-09-20 18:09:56
   * @param {string[]} names
   */
  async dataChangeNotify(names: string[]): Promise<void> {
    // 计算动态控制逻辑
    this.calcDynamicLogic(names);

    // 计算动态样式表
    this.calcDynaClass(this.data);
  }

  /**
   * 表单状态变更通知
   *
   * @author lxm
   * @date 2022-09-20 18:09:07
   */
  async formStateNotify(state: FormNotifyState): Promise<void> {
    // 计算动态控制逻辑
    this.calcDynamicLogic([], state);

    // 计算动态样式表
    this.calcDynaClass(this.data);
  }

  /**
   * 计算动态逻辑
   *
   * @author lxm
   * @date 2022-09-20 19:09:20
   * @protected
   * @param {string[]} names 变更的属性集合
   * @param {FormNotifyState} [state] 表单通知状态
   * @returns {*}  {void}
   */
  protected calcDynamicLogic(names: string[], state?: FormNotifyState): void {
    // 逻辑优化，当父容器存在且为不显示时，不去计算自己的动态逻辑
    if (this.parent && !this.parent.state.visible) {
      return;
    }

    // 根据自身的动态逻辑计算
    this.model.defdgroupLogics?.forEach(logic => {
      const relatedNames = logic.relatedDetailNames || [];
      // name是动态逻辑涉及到的时或state存在时
      if (state || isOverlap(relatedNames, names)) {
        try {
          const ok = verifyFormGroupLogic(this.form.data, logic);
          switch (logic.logicCat) {
            // 动态空输入，不满足则必填
            case 'ITEMBLANK':
              this.state.required = !ok;
              break;
            // 动态启用，满足则启用
            case 'ITEMENABLE':
              this.state.disabled = !ok;
              break;
            // 动态显示，满足则显示
            case 'PANELVISIBLE':
              this.state.visible = ok;
              break;
            default:
          }
        } catch (error) {
          ibiz.log.error(error);
        }
      }
    });
  }

  /**
   * 强制更新视图
   *
   * @author lxm
   * @date 2022-09-15 09:09:05
   * @param {() => void} [_callback] 更新之后，组件渲染完成后的回调
   */
  force(_callback?: () => void): void {
    // 在界面数据发生变更时，会调用此方法。
    // 可外部覆盖实例的此方法，实现自定义的数据更新逻辑。
  }

  /**
   * 计算动态样式表
   * @author lxm
   * @date 2023-08-02 06:15:08
   * @param {IData} data
   */
  protected calcDynaClass(data: IData): void {
    if (this.model.dynaClass) {
      const dynaClass = calcDynaClass(this.model.dynaClass, data);
      if (dynaClass.length) {
        this.state.class.containerDyna = dynaClass;
      }
    }
    if (this.model.labelDynaClass) {
      const dynaClass = calcDynaClass(this.model.labelDynaClass, data);
      if (dynaClass.length) {
        this.state.class.labelDyna = dynaClass;
      }
    }
  }
}
